package com.ht.api.db;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.sql.DataSource;

import com.ht.api.db.bean.Column;
import com.ht.api.db.constant.CacheConstants;
import com.ht.api.db.exception.HtException;
import com.ht.api.db.util.RedisUtil;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 数据翻译
 * @author asq
 * @createTime 2025年1月4日 13:06:49
 */
@Slf4j
public class Mapper {
	/** 一些不能进行翻译的系统表 */
	private static final List<String> SYS_TABLES = Arrays.asList("db_table", "db_column", "sys_dict", "sys_dict_value");

	/**
	 * 翻译单条数据
	 * @param entity
	 */
	public static void translate(Entity entity) {
		translate(DbConfig.useSysDb(), DbList.create(entity));
	}

	/**
	 * 翻译单条数据，指定数据源
	 * @param ds 指定数据源
	 * @param entity
	 */
	public static void translate(DataSource ds, Entity entity) {
		translate(ds, DbList.create(entity));
	}
	
	/**
	 * 为dblist集合注入翻译后的字典数据和外键数据
	 * @param dblist 要翻译的数据列表
	 */
	public static void translate(DbList dblist) {
		translate(DbConfig.useSysDb(), dblist);
	}
	
	/**
	 * 为dblist集合注入翻译后的字典数据和外键数据
	 * @param ds 指定数据源
	 * @param dblist 要翻译的数据列表
	 */
	public static void translate(DataSource ds, DbList dblist) {
		// 系统表不可以翻译
		String table = dblist.getTable();
		if (StrUtil.isBlank(table) || isSystemTable(table)) {
			return;
		}
		
		// 翻译
		translate(ds, table, dblist, true);
	}
	
	/**
	 * 为dblist集合注入翻译后的字典数据和外键数据
	 * @param ds 指定数据源
	 * @param table 表名
	 * @param dblist 数据列表
	 * @param translateMapper 是否翻译外键字段
	 */
	private static void translate(DataSource ds, String table, DbList dblist, boolean translateMapper) {
		if (dblist == null || dblist.isEmpty()) return;
		
		// 翻译字典数据
		translateDict(getColumnMap(table), dblist);
		
		// 翻译字段映射
		if (translateMapper) {
			translateMapper(ds, table, dblist);
		}
	}

	/**
	 * 获取缓存中所有的字典数据
	 * @param table
	 * @return
	 */
	private static Map<String, Map<String, JSONObject>> getColumnMap(String table) {
		List<Column> columns = DbConfig.columnList(table);
		
	    // 1. 只获取有字典设置的列
	    List<Column> dictColumns = columns.stream()
	        .filter(col -> col.getDict() != null && col.getDict() != 0)
	        .collect(Collectors.toList());
	    if (dictColumns.isEmpty()) {
	        return Collections.emptyMap();
	    }
	    
	    // 2. 收集字典 keys
	    List<String> dictKeys = dictColumns.stream()
	        .map(col -> CacheConstants.KEY_DICT + col.getDict())
	        .collect(Collectors.toList());
	    
	    // 3. 批量获取字典数据
	    @SuppressWarnings("unchecked")
	    List<Map<String, JSONObject>> dictMaps = RedisUtil.mget(dictKeys)
	        .stream()
	        .map(obj -> (Map<String, JSONObject>) obj)
	        .collect(Collectors.toList());
	    
	    // 4. 构建映射（使用 dictColumns 而不是 columns）
	    Map<String, Map<String, JSONObject>> result = new HashMap<>();
	    for (int i = 0; i < dictColumns.size(); i++) {
	        Map<String, JSONObject> dictMap = dictMaps.get(i);
	        if (dictMap != null) {
	            result.put(dictColumns.get(i).getCode(), dictMap);
	        }
	    }
	    
	    return result;
	}
	
	/**
	 * 翻译字典数据
	 * @param map 字典数据
	 * @param dblist 待翻译的数据集合
	 */
	private static void translateDict(Map<String, Map<String, JSONObject>> map, List<Entity> dblist) {
	    for (Entity entity : dblist) {
	        // 创建 keys 的副本
	        Set<String> keys = new HashSet<>(entity.keySet());
	        
	        for (String fieldName : keys) {
	            Map<String, JSONObject> dictMap = map.get(fieldName);
	            
	            if (dictMap != null) {
	                String fieldValue = entity.getStr(fieldName);
	                JSONObject dictValue = dictMap.get(fieldValue);
	                
	                if (dictValue != null) {
	                    entity.set("dict_" + fieldName, dictValue);
	                }
	            }
	        }
	    }
	}
	
	/**
	 * 给dblist中所有数据注入字段映射信息
	 * @param ds 指定数据源
	 * @param table 表名
	 * @param dblist 数据列表
	 */
	private static void translateMapper(DataSource ds, String table, List<Entity> dblist) {
		DbConfig.columnList(table)
	    	.stream()
	        .filter(col -> StrUtil.isNotBlank(col.getMapperConfig()))
	        .forEach(col -> {
	        	translateField(ds, col, dblist);
	        });
	}
	
	/**
	 * 映射外键字段
	 * @param ds 指定数据源
	 * @param col 列对象
	 * @param dblist 数据列表
	 */
	private static void translateField(DataSource ds, Column col, List<Entity> dblist) {
		if (StrUtil.isBlank(col.getMapperConfig())) {
			return;
		}
	    // 获取列的字段映射配置
		JSONObject config = null;
		try {
			config = JSONUtil.parseObj(col.getMapperConfig());
		} catch (JSONException e) {
			throw new HtException(String.format("[%s]列的mapper_config配置错误，无法翻译数据~", col.getCode()));
		}
	    
	    // 获取映射的目标表ID和表名
	    String targetTable = config.getStr("table");;
	    
	    // 获取关联字段和要查询的字段列表
	    String relId = config.getStr("rel_id");
	    List<String> fields = config.getJSONArray("fields").toList(String.class);
	    
	    // 获取所有外键值（去重）
	    Set<String> foreignKeys = dblist.stream()
	        .map(e -> e.getStr(col.getCode()))
	        .filter(StrUtil::isNotEmpty)
	        .collect(Collectors.toSet());
	    
	    if (foreignKeys.isEmpty()) {
	        return;
	    }
	    
	    // 构造查询SQL
	    String fieldsEscape = fields.stream().map(field -> "`" + field + "`").collect(Collectors.joining(","));
	    String select = String.format("`%s`,%s", relId, fieldsEscape);  // 确保包含关联字段
	    DbList resultList = Db.createSqlParser(targetTable).select(select).where(relId, "in", foreignKeys).query(ds);
	    
	    // 外键关联的数据也需要翻译字典
	    resultList.setTable(targetTable); // 设置表名，这样才能成功翻译
	    translate(ds, targetTable, resultList, false); // 注意这里调用翻译时，要传false，否则递归翻译外键，可能会造成死循环
	    
	    // 转换为 Map，key 是关联字段值
	    Map<String, JSONObject> resultMap = resultList.stream()
	        .collect(Collectors.toMap(
	            e -> e.getStr(relId),
	            e -> {
	                JSONObject obj = new JSONObject();
	                fields.forEach(field -> obj.set(field, e.get(field)));
	                
	                // 再加上字典字段
	                e.keySet().stream().filter(k -> k.startsWith("dict_")).forEach(key -> {
	                		obj.set(key, e.get(key));
	                	});
	                
	                return obj;
	            },
	            (v1, v2) -> v1  // 处理可能的重复键
	        ));
	    
	    // 给 dblist 中的每个对象添加映射字段
	    String columnCode = col.getCode();
	    dblist.forEach(entity -> {
	        String foreignKey = entity.getStr(columnCode);
	        if (StrUtil.isNotEmpty(foreignKey)) {
	            JSONObject mappedValue = resultMap.get(foreignKey);
	            if (mappedValue != null) {
	                entity.set("mapper_" + columnCode, mappedValue);
	            }
	        }
	    });
	}
	
	/**
	 * 判断表名是否是系统表
	 * @param table
	 * @return
	 */
	private static boolean isSystemTable(String table) {
		return SYS_TABLES.contains(table);
	}
}
